home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9203.ZIP / BLACKBRD.ASC < prev    next >
Text File  |  1992-01-24  |  18KB  |  536 lines

  1. _PROGRAMMING WITH COMMUNCIATION PROTOCOL STACKS_
  2. by Gordon Free
  3.  
  4. [LISTING ONE]
  5.  
  6. #ifndef FT_H
  7. #define FT_H
  8.  
  9. #define  HVC_FIRST   2
  10. #define  HVC_LAST    5
  11. #define  MAX_VCS     HVC_LAST-HVC_FIRST+1
  12. #define  HDRSIZE     MAX_APPHDRDATA+sizeof(BBHDR)
  13.  
  14. /* Message command values */
  15. #define  FT2_SEND    3
  16. #define  FT2_RECEIVE 4
  17.  
  18. /* Bit fields for Blackbird events */
  19. typedef union {
  20.    struct  {
  21.       unsigned ListenCallback : 1;
  22.       unsigned ConnectCallback : 1;
  23.       unsigned ReadBreathe : 1;
  24.       unsigned ReadCallback : 1;
  25.       unsigned WriteBreathe : 1;
  26.       unsigned WriteCallback : 1;
  27.       unsigned DisconnectCallback : 1;
  28.    }     flags;
  29.    int   all;
  30. } EVENT_T;
  31.  
  32. /* Structure for info on currently open file */
  33. typedef struct _FILEDATA {
  34.    FILE  *hStream;         /* stream handle                         */
  35.    char  *pszName;         /* name of file                          */
  36.    char  *pszOpenMode;     /* mode file is opened in "r", "w", etc. */
  37.    long  lSize;            /* size of file in bytes                 */
  38.    void  *pvBuffer;        /* ptr to buffer of file contents        */
  39. } FILEDATA_T;
  40.  
  41. /* Structure for application service, one per VC */
  42. typedef struct _SVCDATA {
  43.    FILEDATA_T  fdCurFile;           /* current file info       */
  44.    char        bbhXmit[HDRSIZE];    /* BB hdr for sending      */
  45.    char        bbhRcv[HDRSIZE];     /* BB hdr for rcving       */
  46.    char        *pszRemoteName;      /* name of remote machine  */
  47.    long        lBytesSoFar;         /* num bytes xferred       */
  48.    int         fActive;             /* TRUE if VC is active    */
  49.    short       sStatus;             /* status of last BB event */
  50.    EVENT_T     fEvent;              /* BB event flags          */
  51. } SVCDATA_T;
  52.  
  53. /*----- Callback routine prototypes ------*/
  54. void cbRemService (
  55.    unsigned  usNumSvcs   /* Number of remote services  */
  56. );
  57. SHORT cbListen (
  58.    HANDLE   hVC,        /* Virtual connection handle     */
  59.    ULONG    ul1,        /* Nothing at this time          */
  60.    ULONG    ul2         /* Status = SHORT1FROMUL( ul2 )  */
  61. );
  62. SHORT cbConnect (
  63.    HANDLE   hVC,        /* Virtual connection handle     */
  64.    ULONG    ul1,        /* Nothing at this time          */
  65.    ULONG    ul2         /* Status = SHORT1FROMUL( ul2 )  */
  66. );
  67. SHORT cbDisConnect (
  68.    HANDLE   hVC,        /* Virtual connection handle     */
  69.    ULONG    ul1,        /* Nothing at this time          */
  70.    ULONG    ul2         /* Status = SHORT1FROMUL( ul2 )  */
  71. );
  72. SHORT cbRead (
  73.    HANDLE   hVC,        /* Virtual connection handle     */
  74.    ULONG    ul1,        /* Number of bytes read          */
  75.    ULONG    ul2         /* Status = SHORT1FROMUL( ul2 )  */
  76. );
  77. SHORT cbWrite (
  78.    HANDLE   hVC,        /* Virtual connection handle     */
  79.    ULONG    ul1,        /* Number of bytes sent          */
  80.    ULONG    ul2         /* Status = SHORT1FROMUL( ul2 )  */
  81. );
  82. #endif
  83.  
  84.  
  85.  
  86. [LISTING TWO]
  87.  
  88. /*====================================================================
  89.   (c) Copyright 1991, Gordon Free
  90.   All Rights Reserved.
  91. --------------------------------------------------------------------
  92.  Filename: FT.C
  93.  Project: DDJ Article
  94.  $Author$
  95.  $Revision$
  96.  $Date$
  97.  Purpose: Sample file transfer program written for Blackbird API.
  98. ====================================================================*/
  99.  
  100. /*----- Includes ------*/
  101. #include <stdio.h>
  102. #include <conio.h>
  103. #include <malloc.h>
  104. #include <string.h>
  105. #include <dos.h>
  106. #include <fcntl.h>
  107. #include <io.h>
  108. #include <sys\types.h>
  109. #include <sys\stat.h>
  110. #include "vcapi.h"
  111. #include "ft.h"
  112.  
  113. /*----- Local Defines and Typedefs ------ */
  114. #define  ESC         0x1B
  115. #define  BUFF_SIZE   (64*1024-1)
  116.  
  117. /*------ Global Variables -----*/
  118. int            fUpdateServices=FALSE;  /* remote service list has changed */
  119. HANDLE         hvcServer=HVC_NONE;     /* vc handle of remote server      */
  120. SVCDATA_T      svc[MAX_VCS];           /* array of app service info       */
  121. char           acMachineName[MAX_MACHID] = "Unknown";
  122.  
  123. /*---- DisplayServices: prints a report of all available remote services ----*/
  124. void DisplayServices(void)
  125. {
  126.    int            nServices;           /* num of services reported    */
  127.    REMSERVICES    remserv;             /* service info struct         */
  128.    static HANDLE  ahRS[10];            /* array of remote svc handles */
  129.    int            i;
  130.  
  131.    puts("\nList of Remote Machines ...");
  132.    puts("---------------------------");
  133.  
  134.    /* Fill in array of remote service handles */
  135.    nServices = vcQuery(ahRS, HBOUND(ahRS));
  136.  
  137.    /* Report service handle and machine name for each remote service */
  138.    for (i=0; i<nServices; i++) {
  139.       sGetRemSvc(ahRS[i], &remserv);
  140.       printf("   %d) %s on %s %c\n", ahRS[i], remserv.acMachineName
  141.          , remserv.acPortName
  142.          , remserv.fInUse ? '*' : ' ');
  143.    }
  144. }
  145.  
  146. /*-- SendFile: read specified file and hand it to Blackbird for delivery --*/
  147. size_t SendFile (
  148.    HANDLE      vch,           /* handle of virtual connection */
  149.    char        *name          /* name of file */
  150. )
  151. {
  152.    int         size=0;        /* number of bytes read */
  153.    int         fileOut;       /* file stream to read from */
  154.    PBBHDR      pbbhXmit;      /* ptr to BB header */
  155.    SVCDATA_T   *psvc;         /* ptr to service struct for this vc */
  156.  
  157.    printf("Sending %s ...\n", name);
  158.    fileOut = open(name,O_RDONLY|O_BINARY);
  159.    if (fileOut > 0) {
  160.       psvc = &svc[vch-HVC_FIRST];
  161.  
  162.       /* Read contents of file into buffer */
  163.       size = read(fileOut, psvc->fdCurFile.pvBuffer, BUFF_SIZE);
  164.       close(fileOut);
  165.  
  166.       /* Put name into packet header */
  167.       pbbhXmit = (PBBHDR)&(psvc->bbhXmit[0]);
  168.       strcpy(&(pbbhXmit->bAppData[1]), name);
  169.  
  170.       /* Indicate what remote is to do with this data */
  171.       pbbhXmit->bAppData[0] = FT2_RECEIVE;
  172.       pbbhXmit->ubBytesToFollow = strlen(name)+2;
  173.  
  174.       vcWrite(vch,pbbhXmit, psvc->fdCurFile.pvBuffer, size
  175.          , NULL, cbWrite, TWO_SECS);
  176.  
  177.    } else {
  178.       perror("Error opening file");
  179.    }
  180.    return size;
  181. }
  182.  
  183. /*----SaveFile: write contents of buffer into file with specified name----*/
  184. int SaveFile (
  185.    char  *name,
  186.    long  lsize,
  187.    void  far *buffer
  188. )
  189. {
  190.    int        size;
  191.    int        fileIn;
  192.    printf("Saved file = %s\n", name);
  193.    fileIn = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY);
  194.    if (fileIn > 0) {
  195.       size = (size_t) lsize;
  196.       write(fileIn, buffer, size);
  197.       close(fileIn);
  198.    } else {
  199.       perror("Error saving file");
  200.    }
  201.    return 0;
  202. }
  203.  
  204. /*---CheckEvents: polls each virtual connection looking for events that
  205.    have been flagged by the various callback routines.---*/
  206. void CheckEvents ( void )
  207. {
  208.    EVENT_T     evt;
  209.    SVCDATA_T  *psvc;
  210.    PBBHDR      pbbhRcv;
  211.    HANDLE      vch;
  212.    void       *buff;
  213.    int         i;
  214.    /* Loop through all possible virtual connections */
  215.    for (i=0, psvc=svc; i<MAX_VCS; i++, psvc++) {
  216.       /* Check to see if anything happened */
  217.       if (psvc->fEvent.all) {
  218.          /* Get copy of event flags and then reset them. This is done with 
  219.          /* interrupts disabled so that we don't miss any events. */
  220.          _disable();
  221.          evt = psvc->fEvent;
  222.          psvc->fEvent.all = FALSE;
  223.          _enable();
  224.  
  225.          /* ------------------- Listen --------------------------- */
  226.          /* Somebody connected to us, allocate storage and issue a */
  227.          /* read to get file transfer requests. */
  228.          if (evt.flags.ListenCallback) {
  229.             puts("#Listen Callback");
  230.             pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
  231.             if (psvc->fdCurFile.pvBuffer != NULL) {
  232.                vcRead(HVC_FIRST+i,pbbhRcv, psvc->fdCurFile.pvBuffer
  233.                   , BUFF_SIZE, NULL, cbRead, TWO_SECS);
  234.             } else {
  235.                puts("Error allocating memory");
  236.             }
  237.             /* Register a new service for use by other clients */
  238.             buff = malloc(BUFF_SIZE);
  239.             if (buff != NULL) {
  240.                vch = vcListen ("FXFR","DDJ", cbListen, cbDisConnect);
  241.                svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
  242.             } else {
  243.                puts("Error allocating memory");
  244.             }
  245.          }
  246.  
  247.          /* ------------------- Connect -------------------------- */
  248.          /* We've successfully connected to a remote server */
  249.          if (evt.flags.ConnectCallback) {
  250.             puts("#Connect Callback");
  251.             hvcServer = HVC_FIRST+i;
  252.          }
  253.  
  254.          /* ------------------- Read  --------------------------- */
  255.          /* We've gotten a request, so process it! */
  256.          if ((evt.flags.ReadCallback) && (psvc->sStatus == 0)) {
  257.  
  258.             pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
  259.             /* Is it a request to receive a file? */
  260.             if (pbbhRcv->bAppData[0] == FT2_RECEIVE) {
  261.                SaveFile(&(pbbhRcv->bAppData[1]), psvc->lBytesSoFar
  262.                   , psvc->fdCurFile.pvBuffer);
  263.             /* How about send a file? */
  264.             } else if (pbbhRcv->bAppData[0] == FT2_SEND) {
  265.                SendFile(i+HVC_FIRST, &(pbbhRcv->bAppData[1]));
  266.             /* No comprende */
  267.             } else {
  268.                puts("Huh?");
  269.             }
  270.             vcRead(HVC_FIRST+i,pbbhRcv, psvc->fdCurFile.pvBuffer
  271.                , BUFF_SIZE, NULL, cbRead, TWO_SECS);
  272.          }
  273.  
  274.          /* ------------------- Write --------------------------- */
  275.          if ((evt.flags.WriteCallback) && (psvc->sStatus == 0)) {
  276.             puts("#Write Complete");
  277.          }
  278.  
  279.          /* ------------------- Disconnect ---------------------- */
  280.          /* Remote went byebye */
  281.          if (evt.flags.DisconnectCallback) {
  282.             puts("#Disconnect Callback");
  283.             free(psvc->fdCurFile.pvBuffer);
  284.             if (i+HVC_FIRST == hvcServer)
  285.                hvcServer = HVC_NONE;
  286.          }
  287.       }
  288.    }
  289.    if (fUpdateServices) {
  290.       fUpdateServices = FALSE;
  291.       DisplayServices();
  292.    }
  293. }
  294.  
  295. /*---DoUserRequests: check keyboard for activity and process user's
  296.    command. Returns TRUE if user has not requested to exit.---*/
  297. int DoUserRequests ( void )
  298. {
  299.    HANDLE      vch;
  300.    SVCDATA_T  *psvc;
  301.    PBBHDR      pbbhXmit, pbbhRcv;
  302.    int         fContinue=TRUE;
  303.    char        filename[80];
  304.    void       *buff;
  305.    int         c;
  306.  
  307.    if ( kbhit() ) {
  308.       switch (c = getch()) {
  309.  
  310.          /* ------------------- Exit ----------------------------- */
  311.          case ESC:
  312.             fContinue = FALSE;
  313.             break;
  314.  
  315.          /* ------------------- Connect -------------------------- */
  316.          case '0':
  317.          case '1':
  318.          case '2':
  319.          case '3':
  320.          case '4':
  321.          case '5':
  322.          case '6':
  323.          case '7':
  324.          case '8':
  325.          case '9':
  326.  
  327.             /* Disconnect from current server, if any. */
  328.             /* Buffer will be released when disconnect completes */
  329.             if (hvcServer != HVC_NONE) {
  330.                vcDisconnect(hvcServer);
  331.             }
  332.             /* Allocate buffer for new service */
  333.             buff = malloc(BUFF_SIZE);
  334.             if (buff != NULL) {
  335.                /* Connect to remote server */
  336.                vch = vcConnect(c-'0', cbConnect, cbDisConnect, TWO_SECS);
  337.                svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
  338.             } else {
  339.                puts("Error allocating memory");
  340.             }
  341.             break;
  342.  
  343.          /* ------------------- Send File ------------------------ */
  344.          case 's':
  345.          case 'S':
  346.             if (hvcServer != HVC_NONE) {
  347.                psvc = &svc[hvcServer-HVC_FIRST];
  348.                printf("\nEnter name of file to send >");
  349.                scanf("%s", filename);
  350.                SendFile(hvcServer, filename);
  351.             } else {
  352.                puts("You must establish a connection first!");
  353.             }
  354.             break;
  355.  
  356.          /* ------------------- Receive File --------------------- */
  357.          case 'r':
  358.          case 'R':
  359.             if (hvcServer != HVC_NONE) {
  360.                psvc = &svc[hvcServer-HVC_FIRST];
  361.  
  362.                /* Set up ptrs to BB hdrs for receive and send */
  363.                pbbhXmit = (PBBHDR)&(psvc->bbhXmit[0]);
  364.                pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
  365.  
  366.                /* Instruct remote server to send specified file */
  367.                printf("\nEnter name of file to receive >");
  368.                scanf("%s", &(pbbhXmit->bAppData[1]));
  369.                pbbhXmit->bAppData[0] = FT2_SEND;
  370.  
  371.                pbbhXmit->ubBytesToFollow
  372.                   = strlen(&(pbbhXmit->bAppData[1]))+2;
  373.                /* Post read before sending request so that we are ready */
  374.                /* for response */
  375.                vcRead(hvcServer,pbbhRcv, psvc->fdCurFile.pvBuffer
  376.                   , BUFF_SIZE, NULL, cbRead, TWO_SECS);
  377.                /* Send request for file */
  378.                vcWrite(hvcServer,pbbhXmit, NULL, 0, NULL, cbWrite, TWO_SECS);
  379.             } else {
  380.                puts("You must establish a connection first!");
  381.             }
  382.          default:
  383.             break;
  384.       }
  385.  
  386.    }
  387.    return fContinue;
  388. }
  389.  
  390. /*----main: initalize Blackbird and alternate between processing Blackbird 
  391.       events and user requests. ----*/
  392. int main (
  393.    int   argc,
  394.    char  **argv
  395. )
  396. {
  397.    HANDLE      vch;
  398.    void       *buff;
  399.    puts("Blackbird File Transfer Sample Program ver 1.0");
  400.    puts("   (c) Copyright 1991, Gordon Free.");
  401.    puts("   All Rights Reserved.\n");
  402.    puts(vcVersion());
  403.  
  404.    /* Parse machine name off command line */
  405.    if (argc >= 2) {
  406.       strncpy(acMachineName, argv[1], sizeof(acMachineName-1));
  407.       acMachineName[sizeof(acMachineName-1)] = '\0';
  408.    }
  409.  
  410.    /* Initialize Blackbird and request notification of remote services */
  411.    vcInit(acMachineName,"DDJ");
  412.    vcRemsvcUpdate(cbRemService);
  413.  
  414.    /* Register as a server only if user gave a machine name */
  415.    if (argc >= 2) {
  416.       buff = malloc(BUFF_SIZE);
  417.       if (buff != NULL) {
  418.          vch = vcListen ("FXFR","DDJ", cbListen, cbDisConnect);
  419.          svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
  420.       } else {
  421.          puts("Error allocating memory");
  422.          goto finish;
  423.       }
  424.    }
  425.  
  426.    /* Alternate between checking for Blackbird events and processing 
  427.       user requests. */
  428.    do
  429.    {
  430.       CheckEvents();
  431.    } while (DoUserRequests());
  432. finish:
  433.    puts("Exiting ...");
  434.    vcEnd();
  435.    return 0;
  436. }
  437.  
  438.  
  439.  
  440. [LISTING THREE]
  441.  
  442. /*--------------------------------------------------------------------
  443.   (c) Copyright 1991, Gordon Free
  444.   All Rights Reserved.
  445. ====================================================================
  446.  Filename: FT_CB.C
  447.  Project: DDJ Article
  448.  $Author$
  449.  $Revision$
  450.  $Date$
  451.  Purpose: Callback routines for Blackbird events
  452. ====================================================================*/
  453.  
  454. /*-----Includes-----*/
  455. #include <stdio.h>
  456. #include "vcapi.h"
  457. #include "ft.h"
  458.  
  459. /*------Global Variables ------*/
  460. extern   SVCDATA_T      svc[MAX_VCS];     /* service info for each VC    */
  461. extern   int            fUpdateServices;  /* set TRUE to display remotes */
  462.  
  463. /* These routines are called at interrupt time, so no stack checking! */
  464. #pragma check_stack(off)
  465.  
  466. /* Called whenever remote service list changes */
  467. void cbRemService (
  468.    unsigned  usNumSvcs   /* Number of remote services  */
  469. )
  470. {
  471.    fUpdateServices = TRUE;
  472. }
  473. /* Called when remote machine connects to us as a client */
  474. SHORT cbListen (
  475.    HANDLE   hVC,     /* Virtual connection handle     */
  476.    ULONG    ul1,     /* Nothing at this time          */
  477.    ULONG    ul2      /* Status = SHORT1FROMUL( ul2 )  */
  478. )
  479. {
  480.    svc[hVC-HVC_FIRST].fEvent.flags.ListenCallback = TRUE;
  481.    svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
  482.    svc[hVC-HVC_FIRST].fActive = TRUE;
  483.    return (FALSE);
  484. }
  485. /* Called when remote server acknowledges our connection request */
  486. SHORT cbConnect (
  487.    HANDLE   hVC,     /* Virtual connection handle     */
  488.    ULONG    ul1,     /* Nothing at this time          */
  489.    ULONG    ul2      /* Status = SHORT1FROMUL( ul2 )  */
  490. )
  491. {
  492.    svc[hVC-HVC_FIRST].fEvent.flags.ConnectCallback = TRUE;
  493.    svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
  494.    svc[hVC-HVC_FIRST].fActive = TRUE;
  495.    return (FALSE);
  496. }
  497. /* Called anytime a VC is broken */
  498. SHORT cbDisConnect (
  499.    HANDLE   hVC,     /* Virtual connection handle     */
  500.    ULONG    ul1,     /* Nothing at this time          */
  501.    ULONG    ul2      /* Status = SHORT1FROMUL( ul2 )  */
  502. )
  503. {
  504.    svc[hVC-HVC_FIRST].fEvent.flags.DisconnectCallback = TRUE;
  505.    svc[hVC-HVC_FIRST].fActive = FALSE;
  506.    return (FALSE);
  507. }
  508. /* Called when we've receive a data buffer from remote */
  509. SHORT cbRead (
  510.    HANDLE   hVC,     /* Virtual connection handle     */
  511.    ULONG    ul1,     /* Number of bytes received      */
  512.    ULONG    ul2      /* Status = SHORT1FROMUL( ul2 )  */
  513. )
  514. {
  515.    svc[hVC-HVC_FIRST].fEvent.flags.ReadCallback = TRUE;
  516.    svc[hVC-HVC_FIRST].lBytesSoFar = ul1;
  517.    svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
  518.  
  519.    return (FALSE);
  520. }
  521. /* Called when data has been successfully sent to remote */
  522. SHORT cbWrite (
  523.    HANDLE   hVC,     /* Virtual connection handle     */
  524.    ULONG    ul1,     /* Nothing at this time          */
  525.    ULONG    ul2      /* Status = SHORT1FROMUL( ul2 )  */
  526. )
  527. {
  528.    svc[hVC-HVC_FIRST].fEvent.flags.WriteCallback = TRUE;
  529.    svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
  530.  
  531.    return (FALSE);
  532. }
  533. #pragma check_stack()
  534.  
  535.  
  536.